# -*- coding: utf-8 -*-
import base64
import json
import time
from collections import OrderedDict

import requests
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
from Crypto.Hash import MD5
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5
from django.conf import settings

from async import async_job
from common.order import db as order_db
from common.order.model import PAY_STATUS
from common.utils import track_logging
from common.utils.exceptions import ParamError

_LOGGER = track_logging.getLogger(__name__)

APP_CONF = {
    'BOPAY000402001401': {
        'API_KEY': 'd8a4e406ffc09536dd338bc3c1a25dcf101fa0cb',
    }
}

_bopay_key = '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+RFtFfpFA7u+iHt1NPLzPZ/gT
eKG7tPvLeZdsxrPmBxbTFlhleQqIJXmGv3LSZ8piPNf8dxfmRGamAu1sw/ufVKFo
ZtvxshHO2lHd/rgA4sXGasJ0egsvHNUUDTHnywk/SKeMGWMSvk3eN+E3gM/DAjqc
JGvr3hOcIbarVBEB3wIDAQAB
-----END PUBLIC KEY-----
'''

_my_public_key = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu8BXMMpUZmoNjmOKkCqSbM4uy
YatSzq+2C+dYJZrZm8255gdP4wsByGw65HvCGCKiBOHbGxseIhfjGjXoJ+p5ufiK
QMtklghfrAo1cTW9byoReJkvyAMsfEp1RgKCTd4uP/9hSX5QHmYXyz+9cvBjy4Bw
nfRU5brJfvtm/EuWkwIDAQAB
-----END PUBLIC KEY-----"""

_my_private_key = """-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAK7wFcwylRmag2OY
4qQKpJszi7Jhq1LOr7YL51glmtmbzbnmB0/jCwHIbDrke8IYIqIE4dsbGx4iF+Ma
Negn6nm5+IpAy2SWCF+sCjVxNb1vKhF4mS/IAyx8SnVGAoJN3i4//2FJflAeZhfL
P71y8GPLgHCd9FTlusl++2b8S5aTAgMBAAECgYBqf+slR14SGkkG51qC95/ChJz1
WhSM8xtxvsl2ll4xQHL8S5gEAHsA+N069UKKpVrgPAyr8VKPA757GcfbsAFEXCkc
RqJyj6MHeLXdFzQlo7sqsGlozIdV28eIjwl+MoJkjEP4HIkfFyd6QChAjdtrHTOP
bgsQt7DvJpvi+jsDQQJBANs3AQBxs5eS7KY4FJBLLAObuad5iQbBSjqrJ4vOw/Jm
MPjpUV/e4UooXtnDG5s/7qkR7Z/aZ5lfe5OscxsJ/xECQQDMSwk1RWUqNUqZ8Lxa
Xry+g7Bt9uzmI0MwBQoOho7dBitN739V/LqueINRVMt76OpRptsrNILvkMKVmtXP
5MNjAkAHLZvoydBZrEP3hWqW9v8v9w9zPnWQNRAbL7ORzml4LIR6AhnaC9BQv1Wr
x8nFoahM/PtM+rfdu9SuFz2FqyQhAkBH6T3Th5rlsZ6R84CJmwF7WmWXP60CEXWM
CKoSlODjAlHp/Bzpiq23zmoDDgMWmdUpar+JRNG2PFGSUc9jf5YbAkEA2w/46pcX
GHlH3vSYHkTHwqZUNjwJoyR+xX+HGeLEm7ffoKcFxTQbeYPY5DajQcyV6/F4n0t/
FFUwPhodE/YuFA==
-----END PRIVATE KEY-----"""

_TEST_GATEWAY = 'http://www.yunjieao.cn/api/pay/qqPay'


def rsa_long_encrypt(pub_key_str, msg, length=117):
    """
    单次加密串的长度最大为 (key_size/8)-11
    1024bit的证书用100， 2048bit的证书用 200
    """
    pubobj = RSA.importKey(pub_key_str)
    pubobj = Cipher_pkcs1_v1_5.new(pubobj)
    res = []
    for i in range(0, len(msg), length):
        res.append(pubobj.encrypt(msg[i:i + length]))
    return "".join(res)


def rsa_long_decrypt(priv_key_str, msg, length=128):
    """
    1024bit的证书用128，2048bit证书用256位
    """
    privobj = RSA.importKey(priv_key_str)
    privobj = Cipher_pkcs1_v1_5.new(privobj)
    res = []
    for i in range(0, len(msg), length):
        res.append(privobj.decrypt(msg[i:i + length], 'xyz'))
    return "".join(res)


def _gen_sign(message, the_key):
    key = RSA.importKey(the_key)
    h = MD5.new(message)
    signer = Signature_pkcs1_v1_5.new(key)
    signature = signer.sign(h)
    signature = base64.b64encode(signature)
    return signature


def _build_common_head(context, appid):
    parameter_dict = OrderedDict((
        ('charset', '00'),
        ('version', 'V1.0'),
        ('merchantNumber', appid),
        ('requestTime', time.strftime("%Y%m%d%H%M%S")),
        ('tradeType', 'qqPayApi'),
        ('signType', 'RSA'),
    ))
    parameter_dict['sign'] = _gen_sign(context, _my_private_key)
    return json.dumps(parameter_dict, sort_keys=True)


def _build_business_Context(orderid, pay_amount, payType, app_id):
    parameter_dict = OrderedDict()
    parameter_dict['amount'] = pay_amount
    parameter_dict['currency'] = 'CNY'
    parameter_dict['payType'] = payType
    parameter_dict['orderNumber'] = orderid
    parameter_dict['commodityName'] = "王小二"
    parameter_dict['commodityDesc'] = "王小二"
    parameter_dict['commodityRemark'] = "王小二"
    parameter_dict['notifyUrl'] = '{}/pay/api/{}/bopay/{}'.format(settings.NOTIFY_PREFIX, settings.NOTIFY_PATH, app_id)
    parameter_dict['authCode'] = ""
    parameter_dict['orderCreateIp'] = "22.22.2.2"
    parameter_dict['terminalId'] = "11"
    return json.dumps(parameter_dict, sort_keys=True, separators=(',', ':'), ensure_ascii=False)


def urlsafe_b64decode(rsp_context):
    rsp_context.replace('-', '+').replace('_', '/')
    mod4 = len(rsp_context) % 4
    if mod4 > 0:
        rsp_context += '===='[mod4:]
    return base64.b64decode(rsp_context)


def create_charge(pay, pay_amount, info):
    ''' 创建订单 '''
    charge_resp = {}
    app_id = info['app_id']
    service = info.get('service')
    if service == 'alipay':
        payType = 'QQ_NATIVE'
    else:
        payType = 'QQ_NATIVE'

    _LOGGER.info("bopay create charge data: %s %s %s", pay.id, int(pay_amount * 100), payType)
    context = _build_business_Context(pay.id, int(pay_amount * 100), payType, app_id)
    head = _build_common_head(context, app_id)
    # head = _build_common_head(context.decode('string_escape'))
    s = '{"businessContext" : %s, "businessHead": %s}' % (context, head)
    my_rsa = rsa_long_encrypt(_bopay_key, s)
    b = base64.b64encode(my_rsa)
    p = {"context": b}

    response = requests.post(_TEST_GATEWAY, json=p, timeout=3)
    _LOGGER.info("bopay create charge data: %s %s", response.status_code, response.text)
    res_obj = json.loads(response.text)
    if res_obj["message"]["code"] != 200:
        _LOGGER.error("bopay create charge err: %s", response.text)
        return charge_resp

    tmp = urlsafe_b64decode(json.dumps(res_obj['context']))
    tmp = rsa_long_decrypt(_my_private_key, tmp)
    j = json.loads(tmp)

    third_id = j['businessContext']['bopayOrderNumber']
    order_db.fill_third_id(pay.id, third_id)

    charge_resp.update({
        'charge_info': j['businessContext']['qrcode'].decode('gbk'),
    })
    return charge_resp


def check_notify_sign(request, app_id):
    _LOGGER.info("bopay notify body: %s", request.body)
    tmp_json = json.loads(request.body)
    tmp = urlsafe_b64decode(tmp_json['context'])
    tmp = rsa_long_decrypt(_my_private_key, tmp)
    _LOGGER.info("bopay notify data: %s", tmp)
    j = json.loads(tmp)
    pay_id = j['businessContext']['orderNumber']
    if not pay_id:
        _LOGGER.error("fatal error, out_trade_no not exists, data: %s" % data)
        raise ParamError('bopay event does not contain pay ID')

    pay = order_db.get_pay(int(pay_id))
    if not pay:
        raise ParamError('pay_id: %s invalid' % pay_id)
    if pay.status != PAY_STATUS.READY:
        raise ParamError('pay %s has been processed' % pay_id)

    mch_id = j['businessHead']['merchantNumber']
    trade_status = j['businessContext']['tradeState']
    trade_no = j['businessContext']['bopayOrderNumber']
    total_fee = float(j['businessContext']['amount']) / 100.00

    extend = {
        'trade_status': trade_status,
        'trade_no': trade_no,
        'total_fee': total_fee
    }

    from common.channel.pay import check_channel_order
    check_channel_order(pay_id, total_fee, app_id)

    if trade_status == 'SUC':
        _LOGGER.info('bopay check order success, mch_id:%s pay_id:%s' % (mch_id, pay_id))
        res = order_db.add_pay_success(mch_id, pay_id, total_fee, trade_no, extend)
    async_job.notify_mch(pay_id)


_TEST_QUERY_GATEWAY_ = 'http://www.yunjieao.cn/api/query/queryTradeOrder'


def query_charge(pay_order, app_id):
    ''' 查询订单 '''
    pass
    # # prepare param
    # businessContext = '{"bopayOrderNumber":"%s"}' % pay_order.third_id
    # sign = _gen_sign(businessContext, _my_private_key)
    # businessHead = '{"merchantNumber":"%s","sign":"%s"}' % (app_id, sign)
    # s = '{"businessContext":%s,"businessHead":%s}' % (businessContext, businessHead)
    # my_rsa = rsa_long_encrypt(_bopay_key, s)
    # b = base64.b64encode(my_rsa)
    # result = {"context": b}
    # response = requests.post(_TEST_QUERY_GATEWAY_, json=result, timeout=3)
    # data = json.loads(response.text)
    # if response.status_code == 200 and data['success']:
    #     tmp = urlsafe_b64decode(json.dumps(data['context']))
    #     tmp = rsa_long_decrypt(_my_private_key, tmp)
    #     j = json.loads(tmp)
    #
    #     trade_status = j['businessContext']['tradeState']
    #     trade_no = j['businessContext']['bopayOrderNumber']
    #     total_fee = float(j['businessContext']['amount']) / 100.00
    #
    #     extend = {
    #         'trade_status': trade_status,
    #         'trade_no': trade_no,
    #         'total_fee': total_fee
    #     }
    #
    #     if trade_status == 'SUC':
    #         _LOGGER.info('bopay query order success, user_id:%s pay_id:%s' % (pay_order.mch_id, pay_order.id))
    #         res = order_db.add_pay_success(pay_order.mch_id, pay_order.id,
    #                                        total_fee, trade_no, extend)
    #         if res:
    #             # async notify
    #             async_job.notify_mch(pay_order.id)
    #         print("order process successfully. %s" % pay_order.id)
    # else:
    #     _LOGGER.warn('bopay data error, status_code: %s', response.status_code)
